package com.the8thfold.anton.ant

import grails.plugins.springsecurity.Secured
import com.the8thfold.anton.utils.QuickId
import com.the8thfold.anton.users.User
import org.apache.tools.ant.Project
import org.apache.tools.ant.ProjectHelper
import com.the8thfold.anton.users.Roles
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils

class JobController {

    def springSecurityService

    @Secured(['ROLE_JOB_RUN'])
    def index = {
        redirect(action: "list", params: params)
    }

    @Secured(['ROLE_JOB_RUN'])
    def list = {
        if (SpringSecurityUtils.ifAllGranted(Roles.ROLE_ADMIN.toString())) {
            if (params.scriptId) {
                [script: AntScript.findByScriptId(params.scriptId), jobs: AntJob.findAllByScript(AntScript.findByScriptId(params.scriptId))]
            }
            else {
                [jobs: AntJob.list()]
            }
        } else {
            User user = User.findByUserId(springSecurityService.principal.userId)
            def jobs = []
            if (params.scriptId) {
                AntJobUser.findAllByUser(user).each {
                    if (it.job.script.scriptId == params.scriptId) {
                        jobs.add(it.job)
                    }
                }
                [script: AntScript.findByScriptId(params.scriptId), jobs: jobs]
            }
            else {
                [jobs: AntJobUser.findAllByUser(user).collect {it.job}]
            }
        }

    }

    @Secured(['ROLE_JOB_RUN'])
    def view = {
        if (params.id) {
            def job = AntJob.findByJobId(params.id)
            def notifiedMap = [:]
            AntJobUser.findAllByJob(job).each {
                if (it.notify){
                    notifiedMap.put(it.user.userId, "checked='true'")
                }
            }
            [job: job, notifiedMap: notifiedMap]
        }
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def updateUsers = {
        if (params.id){
            AntJob job = AntJob.findByJobId(params.id)

            def jobUsers = AntJobUser.findAllByJob(job)

            jobUsers.each {
                it.notify = false
                it.save(flush:true, failOnError: true)
            }
            if (params.users){

                [params.users].flatten().each {
                    User user = User.findByUserId(it)
                    AntJobUser jobUser = AntJobUser.findByUserAndJob(user,job)
                    jobUser.notify = true
                    jobUser.save(flush:true, failOnError: true)
                }
            }
        }
        render("")
    }

    def create = {
        if (springSecurityService.isLoggedIn()) {
            AntJob antJob = new AntJob()
            antJob.jobId = QuickId.newId
            antJob.jobStatus = JobStatus.ACTIVE
            if (params.scriptId) {
                AntScript script = AntScript.findByScriptId(params.scriptId)
                antJob.name = "Job #"+ (AntJob.countByScript(script)+1) +" for " + script.description
                antJob.description = "Job for " + script.description
                antJob.script = script
            }
            def scripts = []
            if (SpringSecurityUtils.ifAllGranted(Roles.ROLE_ADMIN.toString())){
                scripts = AntScript.findAll()
            } else {
                User user = User.findByUserId(springSecurityService.principal.userId)
                scripts = AntScriptUser.findAllByUser(user).collect {it.script} as Set
            }
            [scripts: scripts, job: antJob]
        }
        else {
            redirect(action: 'list')
        }
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def save = {
        if (params.jobId){
            User user = User.findById(springSecurityService.principal.id)
            AntJob job = new AntJob(params)
            job.script = AntScript.findByScriptId(params.scriptId)
            job.createdBy = user
            job.dateCreated = new Date()
            job.save(flush: true, failOnError: true)

            job.addToUsers(new AntJobUser(job: job, user: user))

            redirect(action: 'view', id: params.jobId, params: params)
        } else {
            redirect(action: 'create', scriptId: params.script, params: params)
        }
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def delete = {
        if (params.id){
            AntJob job = AntJob.findByJobId(params.id)
            if (job){
                job.delete(flush: true, failOnError: true)
            }
        }
        if (params.origin){
            redirect(url: params.origin.decodeURL(), params: params)
        } else {
            redirect(action: 'list', params: params)
        }
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def pause = {
        if (params.id){
            AntJob job = AntJob.findByJobId(params.id)
            if (job && JobStatus.ACTIVE.equals(job.jobStatus)) {
                job.jobStatus = JobStatus.PAUSED
            }
        }
        redirect(url: params.origin.decodeURL())
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def activate = {
        if (params.id){
            AntJob job = AntJob.findByJobId(params.id)
            if (job && JobStatus.PAUSED.equals(job.jobStatus)) {
                job.jobStatus = JobStatus.ACTIVE
            }
        }
        redirect(url: params.origin.decodeURL())
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def addProperty = {
        if (params.id && params.jobprop) {
            AntJob job = AntJob.findByJobId(params.id)
            params.each { key, value ->
                if (!key.equals("jobprop.") && key.startsWith("jobprop.")){
                    def paramKey = key.toString().substring(key.toString().lastIndexOf("jobprop.")+"jobprop.".length())
                    job.addToPropertyValues(new AntJobPropertyValue(
                            propertyId: QuickId.newId,
                            name: paramKey,
                            value: params["jobpropvalue.$paramKey"],
                            defaultValue: params["jobpropvalue.$paramKey"]
                    ))
                }
            }
        }
        redirect(action: 'view', id: params.id)
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def deleteProperty = {
        def jobId
        if (params.id) {
            AntJobPropertyValue propertyValue = AntJobPropertyValue.findByPropertyId(params.id)
            jobId = propertyValue.job.jobId
            propertyValue.delete(flush: true, failOnError: true)
        }
        redirect(action: 'view', id: jobId, params: params)
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def updateProperty = {
        if (params.id) {
            AntJobPropertyValue propertyValue = AntJobPropertyValue.findByPropertyId(params.propertyId)
            propertyValue.value = params.value
            propertyValue.save(flush: true, failOnError: true)
        }
        //redirect(action: 'view', id: jobId, params: params)
        render(template: "propertiesTable", model: [job: AntJob.findByJobId(params.id)])
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def restoreDefault = {
        def jobId
        def value
        if (params.id) {
            AntJobPropertyValue propertyValue = AntJobPropertyValue.findByPropertyId(params.id)
            propertyValue.value = propertyValue.defaultValue
            jobId = propertyValue.job.jobId
            value = propertyValue.value
            propertyValue.save(flush: true, failOnError: true)
        }
        render(value)
        //redirect(action: 'view', id: jobId, params: params)
        //render(template: "propertiesTable", model: [job: AntJob.findByJobId(jobId)])
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def propertySelect = {
        if (params.id) {
            AntJob job = AntJob.findByJobId(params.id)

            File buildFile = new File(job.script.scriptFilePath)
            Project antProject = new Project();
            antProject.setUserProperty("ant.file", buildFile.getAbsolutePath());
            ProjectHelper helper = ProjectHelper.getProjectHelper();
            antProject.init();
            antProject.addReference("ant.projectHelper", helper);
            helper.parse(antProject, buildFile);
            def props = System.properties
            def projectProperties = new Properties(antProject.properties)
            props.each {key, value ->
                projectProperties.remove(key);
            }
            antProject.properties.each { key, value ->
                if (key.startsWith("ant"))
                    projectProperties.remove(key);
            }
            projectProperties.sort {a, b ->
                a.toString().compareTo(b.toString())
            }

            job.propertyValues.each { item ->
                projectProperties.remove(item.name)
            }

            [job: job, projectProperties: projectProperties]
        }
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def targetSelect = {
        if (params.id) {
            AntJob job = AntJob.findByJobId(params.id)

            File buildFile = new File(job.script.scriptFilePath)
            Project antProject = new Project();
            antProject.setUserProperty("ant.file", buildFile.getAbsolutePath());
            ProjectHelper helper = ProjectHelper.getProjectHelper();
            antProject.init();
            antProject.addReference("ant.projectHelper", helper);
            helper.parse(antProject, buildFile);

            def targets = [:]

            antProject.targets.each { key, value ->
                if (AntJobTarget.countByNameAndJob(key, job) == 0) {
                    targets.put(key, value)
                }
            }

            [job: job, antProject: antProject, targets: targets.sort()]
        }
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def addTarget = {
        if (params.id && params.jobtarget) {
            AntJob job = AntJob.findByJobId(params.id)
            def targetsCounter = AntJobTarget.countByJob(job) + 1
            params.each { key, value ->
                if (!key.equals("jobtarget.") && key.startsWith("jobtarget.")){
                    def paramKey = key.toString().substring(key.toString().lastIndexOf("jobtarget.")+"jobtarget.".length())
                    job.addToTargets(new AntJobTarget(
                            targetId: QuickId.newId,
                            name: paramKey,
                            description: "",
                            ordinal: targetsCounter++
                    ))
                }
            }
        }
        redirect(action: 'view', id: params.id)
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def deleteTarget = {
        def jobId
        if (params.id) {
            AntJobTarget target = AntJobTarget.findByTargetId(params.id)
            jobId = target.job.jobId
            target.delete(flush: true, failOnError: true)
        }
        redirect(action: 'view', id: jobId, params: params)
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def upTarget = {
        def jobId
        if (params.id) {
            AntJobTarget target = AntJobTarget.findByTargetId(params.id)
            AntJobTarget prevTarget = AntJobTarget.findByJobAndOrdinal(target.job, target.ordinal - 1 )
            jobId = target.job.jobId

            if (prevTarget) {
                def tempOrdinal = target.ordinal
                target.ordinal = prevTarget.ordinal
                prevTarget.ordinal = tempOrdinal
                target.save(flush: true, failOnError: true)
                prevTarget.save(flush: true, failOnError: true)
            }
        }
        redirect(action: 'view', id: jobId, params: params)
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def downTarget = {
        def jobId
        if (params.id) {
            AntJobTarget target = AntJobTarget.findByTargetId(params.id)
            AntJobTarget lowerTarget = AntJobTarget.findByJobAndOrdinal(target.job, target.ordinal + 1 )
            jobId = target.job.jobId

            if (lowerTarget) {
                def tempOrdinal = target.ordinal
                target.ordinal = lowerTarget.ordinal
                lowerTarget.ordinal = tempOrdinal
                target.save(flush: true, failOnError: true)
                lowerTarget.save(flush: true, failOnError: true)
            }
        }
        redirect(action: 'view', id: jobId, params: params)
    }

    @Secured(['ROLE_JOB_ADMIN'])
    def updateField = {
        if (params.id){
            AntJob job = AntJob.findByJobId(params.id)
            job.properties.put(params.field, params.value)
            job.save(flush: true, failOnError: true)
        }
        render("")
    }

    @Secured(['ROLE_JOB_RUN'])
    def run = {
        if (params.id) {
            AntJob job = AntJob.findByJobId(params.id)
            AntJobRunResults result = new AntJobRunResults(
                    runResultsId: QuickId.newId,
                    name: "$job.name [${new Date()}]",
                    runLog: "",
                    dateCreated: new Date(),
                    createdBy: User.findByUserId(springSecurityService.principal.userId),
                    status: AntJobStatus.CREATED
            )
            job.addToRunResults(result)

            job.users.each {
                if (it.notify) {
                    result.addToNotifiedUsers(it.user)
                }
            }

            redirect(controller: 'result', action: 'list', params: params)
        } else {
            redirect(action: 'view', id: params.id, params: params)
        }
    }
}
